// ==UserScript==
// @name         EnhancedTouchWork
// @namespace    http://tampermonkey.net/
// @version      2025-06-01
// @description  Enhanced touch support for LCEDA Pro editor
// @author       You
// @match        https://pro.lceda.cn/editor
// @icon         https://www.google.com/s2/favicons?sz=64&domain=lceda.cn
// @grant        GM_addStyle
// ==/UserScript==

/**
 * 运行环境描述：
 * - 该脚本运行在 LCEDA Pro 编辑器中，编辑器中包含多个 iframe，每个 iframe 中包含一个 svg 文件，svg 文件中包含一个 gridBg 的画布元素
 * - 用户在PC上操作时，鼠标事件如下
 *  - 单击：选中画布上的元素
 *  - 右击：打开上下文菜单
 *  - 左键点击拖拽：框选元素
 *  - 右键点击拖拽：拖动画布
 *  - 滚动：缩放画布
 *
 * 需求描述：
 * 现需要将PC上的鼠标事件映射到画布上，实现画布的触摸支持，并实现以下功能：
 * - 在画布上添加一个触摸层，用于接收触摸事件，并映射到画布上
 * - 单指点击：选中画布上的元素
 * - 单指若未选中元素，则拖动画布
 * - 双指捏合：缩放画布
 * - 右下角为操作按钮
 *  - 包含：shift、ctrl、meta、alt可以结合单指操作使用
 *  - 添加鼠标左键(按键上展示左键或框选的emoji)，勾选后，单指点击拖拽将框选元素，取消之前的拖动画布操作
 *  - 添加鼠标右键(按键上展示右键或上下文菜单的emoji), 勾选后，单指点击画布，将打开上下文菜单
 *  - 对于一些小的点或线不太好选中或拖动，需要添加一种操作模式(光标模式)
 *   - 选中后，在屏幕中间出现一个光标，此时可以结合鼠标左、右键和拖动来控制该光标的移动和精准点击事件
 *
 * 体验优化：
 * - 单击选中元素后，再次拖动将是移动元素，而不是拖动画布（右键改左键）
 */

GM_addStyle(`
  #touch-bottom-panel {
    position: fixed;
    left: 10px;
    right: 10px;
    bottom: 16px;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 8px;
    border: 1px soild rgba(0, 0, 0, 0.5);
    border-radius: 8px;
    padding: 10px;
    overflow: auto;
    font-family: monospace;
    font-size: 12px;
    z-index: 10000;
    pointer-events: none;
  }
  #touch-debug-panel {
    background: rgba(0, 0, 0, 0.5);
    color: white;
    border-radius: 8px;
    padding: 10px;
    width: 100%;
    box-sizing: border-box;
    max-height: 150px;
    overflow: auto;
    font-size: 10px;
    transition: opacity 0.2s;
  }

  #touch-fab-group {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 14px;
    pointer-events: auto;
  }

  .touch-fab-btn-list {
    display: flex;
    flex-direction: row;
    gap: 8px;
    background: rgba(30,30,30,0.35);
    border-radius: 16px;
    padding: 2px 4px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.12);
    transition: all 0.3s ease;
    overflow: hidden;
  }

  .touch-fab-btn-list.collapsed {
    width: 0;
    padding: 2px 0;
    gap: 0;
  }

  .touch-fab-btn {
    background: rgba(30,30,30,0.35);
    color: #fff;
    border: none;
    border-radius: 16px;
    padding: 4px 8px;
    font-size: 14px;
    min-width: 28px;
    cursor: pointer;
    transition: background 0.2s, color 0.2s;
    outline: none;
    white-space: nowrap;
  }

  .touch-fab-btn.active {
    background: linear-gradient(145deg, #00b09b, #96c93d);
    color: #fff;
    font-weight: bold;
  }

  .touch-fab-btn.enabled {
    background: linear-gradient(145deg, #00b09b, #96c93d);
    color: #fff;
    font-weight: bold;
  }

  .touch-fab-btn.mouse-state {
    min-width: 32px;
    font-weight: bold;
  }

  .touch-fab-btn.mouse-state.left {
    background: linear-gradient(145deg, #4CAF50, #45a049);
  }

  .touch-fab-btn.mouse-state.right {
    background: linear-gradient(145deg, #f44336, #da190b);
  }

  .touch-fab-btn.mouse-state.none {
    background: rgba(30,30,30,0.35);
  }
`);

(function () {
  "use strict";

  // 配置常量
  const CONFIG = {
    LONG_PRESS_DELAY: 500,
    SINGLE_FINGER_DELAY: 100,
    MOVE_THRESHOLD: 8,
    DISTANCE_THRESHOLD: 12,
    ZOOM_SENSITIVITY: 0.6,
    ZOOM_SMOOTHING: 0.25,
    ZOOM_MIN_DELAY: 500, // 双指点击的最大时长（毫秒）
    ZOOM_MIN_DELTA: 1,
    ZOOM_DISTANCE_THRESHOLD: 5,
  };

  // 默认按钮
  const defaultBtns = [
    // { key: "w", label: "w" },
    { key: "meta", label: "⌘" },
    { key: "cursor", label: "✛" },
    { key: "debug", label: "🐞" },
  ];
  const btnLabel = {
    0: "left",
    2: "right",
  };

  // 全局状态
  let globalState = {
    enabled: false,
    debugPanel: null,
    fabGroup: null,
    activeOverlays: [],
    activeStates: [],
    uiCollapsed: true, // 默认收起状态
  };

  // 渲染按钮
  function renderFabBtns(btnList) {
    btnList.innerHTML = "";
    defaultBtns.forEach((btn) => {
      const el = document.createElement("button");
      el.className = "touch-fab-btn";
      el.setAttribute("data-key", btn.key);
      el.textContent = btn.label;
      btnList.appendChild(el);
    });
  }

  // 创建调试面板和功能按钮组
  function createDebugUI() {
    const bottomPanel = document.createElement("div");
    const debugPanel = document.createElement("div");
    bottomPanel.id = "touch-bottom-panel";
    debugPanel.id = "touch-debug-panel";
    debugPanel.innerHTML = "<div>Touch Debug Panel - Ready to initialize</div>";
    document.body.appendChild(bottomPanel);
    bottomPanel.appendChild(debugPanel);

    // 创建功能按钮组容器
    const fabGroup = document.createElement("div");
    fabGroup.id = "touch-fab-group";
    fabGroup.innerHTML = `
      <button id="touch-fab-enable-toggle" class="touch-fab-btn">🔄</button>
      <button id="touch-fab-mouse-state" class="touch-fab-btn mouse-state none">⬚</button>
      <button id="touch-fab-toggle-ui" class="touch-fab-btn">◀</button>
      <div class="touch-fab-btn-list collapsed" id="touch-fab-btn-list"></div>
    `;
    bottomPanel.insertBefore(fabGroup, debugPanel);

    renderFabBtns(fabGroup.querySelector("#touch-fab-btn-list"));

    // debug面板默认隐藏
    debugPanel.style.display = "none";
    return { debugPanel, fabGroup };
  }

  // 添加调试日志
  function logMessage(message, debugPanel) {
    if (!debugPanel) return;

    const entry = document.createElement("div");
    const now = new Date();
    const timeStr = `${now.getMinutes()}:${now.getSeconds()}.${now.getMilliseconds()}`;
    entry.textContent = `[${timeStr}] ${message}`;
    debugPanel.appendChild(entry);

    // 保持最多10条日志
    while (debugPanel.children.length > 10) {
      debugPanel.removeChild(debugPanel.firstChild);
    }

    // 自动滚动到底部
    debugPanel.scrollTop = debugPanel.scrollHeight;
  }

  // 初始化触摸支持
  function initializeTouchSupport() {
    try {
      logMessage("Initializing touch support...", globalState.debugPanel);

      // 清理之前的覆盖层
      cleanupOverlays();

      // 查找所有iframe
      const iframes = document.querySelectorAll(".editframe");
      logMessage(`Found ${iframes.length} iframes`, globalState.debugPanel);

      iframes.forEach((iframe, index) => {
        try {
          const iframeDoc = iframe.contentDocument;
          if (!iframeDoc) {
            logMessage(
              `Iframe ${index}: Document not accessible`,
              globalState.debugPanel
            );
            return;
          }

          // 查找gridBg或canvas元素
          const gridBg = iframeDoc.getElementById("gridBg");
          const canvas = iframeDoc.getElementById("canvas");
          const targetElement = gridBg || canvas;

          if (targetElement) {
            logMessage(
              `Iframe ${index}: Found ${targetElement.id}`,
              globalState.debugPanel
            );
            initializeForIframe(
              iframe,
              targetElement,
              globalState.debugPanel,
              globalState.fabGroup
            );
          } else {
            logMessage(
              `Iframe ${index}: No gridBg or canvas found`,
              globalState.debugPanel
            );
          }
        } catch (error) {
          logMessage(
            `Iframe ${index}: Error - ${error.message}`,
            globalState.debugPanel
          );
        }
      });

      logMessage(
        "Touch support initialization completed",
        globalState.debugPanel
      );
    } catch (error) {
      logMessage(
        `Error during initialization: ${error.message}`,
        globalState.debugPanel
      );
    }
  }

  // 清理覆盖层
  function cleanupOverlays() {
    globalState.activeOverlays.forEach((overlay) => {
      if (overlay && overlay.parentNode) {
        overlay.parentNode.removeChild(overlay);
      }
    });
    globalState.activeOverlays = [];
    globalState.activeStates = [];
  }

  // 为单个iframe初始化触摸支持
  function initializeForIframe(iframe, svgRect, debugPanel, fabGroup) {
    logMessage(
      `Initializing touch support for iframe: ${iframe.id || "unknown"}`,
      debugPanel
    );
    const iframeDoc = iframe.contentDocument;
    const overlay = createTouchOverlay(iframe, iframeDoc, svgRect);
    const state = setupTouchHandlers(
      overlay,
      svgRect,
      debugPanel,
      fabGroup,
      iframeDoc
    );

    globalState.activeOverlays.push(overlay);
    globalState.activeStates.push(state);
  }

  // 创建触摸覆盖层
  function createTouchOverlay(iframe, iframeDoc, svgRect) {
    const overlay = iframeDoc.createElement("div");
    overlay.id = "touch-overlay";

    updateOverlayPosition(overlay, svgRect);
    iframeDoc.body.appendChild(overlay);

    setupResizeObserver(iframe, svgRect, () =>
      updateOverlayPosition(overlay, svgRect)
    );

    return overlay;
  }

  // 更新覆盖层位置
  function updateOverlayPosition(overlay, svgRect) {
    const rect = svgRect.getBoundingClientRect();
    overlay.style.cssText = `
            position: absolute;
            left: ${rect.left}px;
            top: ${rect.top}px;
            width: ${rect.width}px;
            height: ${rect.height}px;
            background-color: rgba(0, 0, 255, 0.05);
            z-index: 9999;
            pointer-events: auto;
        `;
  }

  // 设置尺寸监听
  function setupResizeObserver(iframe, target, callback) {
    if (window.ResizeObserver) {
      const observer = new iframe.contentWindow.ResizeObserver(callback);
      observer.observe(target);
      return;
    }

    // 降级方案：轮询检测
    let lastRect = JSON.stringify(target.getBoundingClientRect());
    setInterval(() => {
      const currentRect = JSON.stringify(target.getBoundingClientRect());
      if (currentRect !== lastRect) {
        callback();
        lastRect = currentRect;
      }
    }, 500);
  }

  // 设置触摸事件处理器
  function createCursorElement(overlay, state) {
    const cursor = document.createElement("div");
    cursor.innerHTML = "✛";
    cursor.style.cssText = `
      position: fixed;
      width: 16px;
      height: 16px;
      font-size: 10px;
      line-height: 16px;
      text-align: center;
      background: rgba(255, 255, 0, 0.15);
      border: 1px dashed rgba(0, 0, 0, 0.2);
      border-radius: 50%;
      pointer-events: none;
      transform: translate(-50%, -50%);
      z-index: 10000;
      display: none;
    `;

    // Position cursor in center of screen initially
    const rect = overlay.getBoundingClientRect();
    state.cursorMode.position.x = rect.width / 2;
    state.cursorMode.position.y = rect.height / 2;
    cursor.style.left = state.cursorMode.position.x + "px";
    cursor.style.top = state.cursorMode.position.y + "px";

    overlay.appendChild(cursor);
    state.cursorMode.element = cursor;
    return cursor;
  }

  function moveCursor(state, deltaX, deltaY, svgRect, debugPanel) {
    if (!state.cursorMode.active || !state.cursorMode.element) return;

    const speed = 2; // Adjust cursor movement speed
    const x = state.cursorMode.position.x + deltaX * speed;
    const y = state.cursorMode.position.y + deltaY * speed;
    state.cursorMode.position.x = x;
    state.cursorMode.position.y = y;

    dispatchMouseEvent(
      svgRect,
      "mousemove",
      { x, y },
      getBtnByState(state, 0),
      state
    );
    logMessage(`Cursor Move ${x.toFixed(1)}, ${y.toFixed(1)}`, debugPanel);

    state.cursorMode.element.style.left = x + "px";
    state.cursorMode.element.style.top = y + "px";
  }

  // 更新鼠标状态按钮
  function updateMouseStateButton(state, fabGroup) {
    const mouseStateBtn = fabGroup.querySelector("#touch-fab-mouse-state");
    if (!mouseStateBtn) return;

    // 移除所有状态类
    mouseStateBtn.classList.remove("left", "right", "none");

    if (state.leftMouseActive) {
      mouseStateBtn.textContent = "⬚";
      mouseStateBtn.classList.add("left");
    } else if (state.rightMouseActive) {
      mouseStateBtn.textContent = "☰";
      mouseStateBtn.classList.add("right");
    } else {
      mouseStateBtn.textContent = "⬚";
      mouseStateBtn.classList.add("none");
    }
  }

  // 切换鼠标状态
  function cycleMouseState(state, fabGroup, debugPanel) {
    if (state.rightMouseActive) {
      // 右键 -> 无
      state.rightMouseActive = false;
      logMessage("鼠标状态: 右键 -> 无", debugPanel);
    } else {
      // 无 -> 右键
      state.rightMouseActive = true;
      state.cursorMode.active = false;
      if (state.cursorMode.element) {
        state.cursorMode.element.style.display = "none";
      }
      logMessage("鼠标状态: 无 -> 右键", debugPanel);
    }

    updateMouseStateButton(state, fabGroup);
  }

  function setupTouchHandlers(
    overlay,
    svgRect,
    debugPanel,
    fabGroup,
    iframeDoc
  ) {
    const state = {
      twoFinger: null,
      longPress: { active: false, timer: null, start: null },
      singleFinger: {
        pending: false,
        timer: null,
        event: null,
        isDragging: false,
        isSelecting: false,
      },
      zoom: { accumulator: 0, raf: null, lastMid: null },
      drag: { active: false, origin: null },
      keyActive: {
        shift: false,
        ctrl: false,
        meta: false,
      },
      debugPanelVisible: false,
      leftMouseActive: false,
      rightMouseActive: false,
      cursorMode: {
        active: false,
        position: { x: 0, y: 0 },
        element: null,
      },
      twoFingerTap: {
        startTime: null,
      },
    };

    // svg根元素
    const body = document.body;

    // 按钮事件绑定
    function bindFabBtnEvents(iframeDoc) {
      // 鼠标状态按钮
      const mouseStateBtn = fabGroup.querySelector("#touch-fab-mouse-state");
      mouseStateBtn.addEventListener("click", () => {
        cycleMouseState(state, fabGroup, debugPanel);
      });

      // UI展开/收起按钮
      const toggleUiBtn = fabGroup.querySelector("#touch-fab-toggle-ui");
      toggleUiBtn.addEventListener("click", () => {
        globalState.uiCollapsed = !globalState.uiCollapsed;
        const btnList = fabGroup.querySelector("#touch-fab-btn-list");
        btnList.classList.toggle("collapsed", globalState.uiCollapsed);
        toggleUiBtn.textContent = globalState.uiCollapsed ? "◀" : "▶";
      });

      // 其他按钮
      const btns = fabGroup.querySelectorAll(".touch-fab-btn[data-key]");
      btns.forEach((btn) => {
        const key = btn.getAttribute("data-key");
        if (key === "cursor") {
          btn.addEventListener("click", () => {
            state.cursorMode.active = !state.cursorMode.active;
            btn.classList.toggle("active", state.cursorMode.active);

            // 互斥：光标模式时取消鼠标状态
            if (state.cursorMode.active) {
              state.leftMouseActive = false;
              state.rightMouseActive = false;
              updateMouseStateButton(state, fabGroup);

              if (!state.cursorMode.element) {
                createCursorElement(overlay, state);
              }
              state.cursorMode.element.style.display = "block";
            } else if (state.cursorMode.element) {
              state.cursorMode.element.style.display = "none";
            }
            logMessage(
              `光标模式: ${state.cursorMode.active ? "开启" : "关闭"}`,
              debugPanel
            );
          });
        } else if (key === "debug") {
          btn.addEventListener("click", () => {
            const isVisible = debugPanel.style.display !== "none";
            debugPanel.style.display = isVisible ? "none" : "";
            btn.classList.toggle("active", !isVisible);
            logMessage(`Debug panel ${isVisible ? "hidden" : "shown"}`, debugPanel);
          });
        } else {
          btn.addEventListener("click", (e) => {
            e.preventDefault();
            const targetEl = iframeDoc.activeElement;
            if (["ctrl", "shift", "meta", "alt"].includes(key)) {
              state.keyActive[key] = !state.keyActive[key];
              btn.classList.toggle("active", state.keyActive[key]);
              logMessage(
                `${key} ${state.keyActive[key] ? "down" : "up"}`,
                debugPanel
              );
              triggerKey(body, key, state.keyActive[key] ? "keydown" : "keyup");
            } else {
              triggerKey(targetEl, key, "keydown");
              setTimeout(() => {
                triggerKey(targetEl, key, "keyup");
              }, 100);
            }

            e.stopPropagation();
          });
        }
      });
    }
    bindFabBtnEvents(iframeDoc);

    // 触摸事件绑定
    overlay.addEventListener(
      "touchstart",
      handleTouchStart.bind(null, state, svgRect, debugPanel)
    );
    overlay.addEventListener(
      "touchmove",
      handleTouchMove.bind(null, state, svgRect, debugPanel)
    );
    overlay.addEventListener(
      "touchend",
      handleTouchEnd.bind(null, state, svgRect, debugPanel)
    );
    overlay.addEventListener(
      "touchcancel",
      handleTouchCancel.bind(null, state, debugPanel)
    );

    return state;
  }

  // 触摸开始处理
  function handleTouchStart(state, svgRect, debugPanel, e) {
    if (e.touches.length === 2) {
      logMessage("Two-finger touch started", debugPanel);
      handleTwoFingerStart(state, e);
    } else if (e.touches.length === 1) {
      logMessage("Single-finger touch started", debugPanel);
      handleSingleFingerStart(state, e, svgRect, debugPanel);
    }
  }

  function getBtnByState(state, defaultBtn = 0) {
    if (state.leftMouseActive) {
      return 0;
    } else if (state.rightMouseActive) {
      return 2;
    }
    return defaultBtn;
  }

  // 双指开始处理
  function handleTwoFingerStart(state, e) {
    clearSingleFingerState(state);

    const touch1 = { x: e.touches[0].clientX, y: e.touches[0].clientY };
    const touch2 = { x: e.touches[1].clientX, y: e.touches[1].clientY };

    state.twoFinger = {
      touches: [touch1, touch2],
      startDist: calculateDistance(touch1, touch2),
      startMid: calculateMidpoint(touch1, touch2),
    };

    // 初始化双指点击检测
    state.twoFingerTap.startTime = Date.now();

    state.drag.active = false;
    state.zoom.accumulator = 0;
  }

  // 单指开始处理
  function handleSingleFingerStart(state, e, svgRect, debugPanel) {
    state.singleFinger.event = e;
    state.singleFinger.isDragging = false;
    const { clientX: x, clientY: y } = e.touches[0];

    if (state.leftMouseActive || state.rightMouseActive) {
      const button = getBtnByState(state);
      dispatchMouseEvent(svgRect, "mousedown", { x, y }, button, state);
      logMessage(`Touch started (${btnLabel[button]})`, debugPanel);
      return;
    }

    state.singleFinger.pending = true;
    state.singleFinger.timer = setTimeout(() => {
      if (!state.singleFinger.pending) return;

      state.singleFinger.pending = false;
      if (state.cursorMode.active) {
        const touch = {
          x: state.cursorMode.position.x,
          y: state.cursorMode.position.y,
        };
        logMessage("Cursor started", debugPanel);
        dispatchMouseEvent(svgRect, "mousedown", touch, 0, state);
      } else {
        logMessage("Touch started", debugPanel);
        dispatchMouseEvent(svgRect, "mousedown", { x, y }, 0, state);
        state.singleFinger.isSelecting = true;
      }
    }, CONFIG.SINGLE_FINGER_DELAY);
  }

  // 触摸移动处理
  function handleTouchMove(state, svgRect, debugPanel, e) {
    const clientX = e.touches[0].clientX;
    const clientY = e.touches[0].clientY;
    if (state.singleFinger.pending) {
      // 检查是否超过移动阈值
      const preX = state.singleFinger.event.touches[0].clientX;
      const preY = state.singleFinger.event.touches[0].clientY;
      const dx = clientX - preX;
      const dy = clientY - preY;
      const distance = Math.sqrt(dx * dx + dy * dy);

      if (distance > CONFIG.MOVE_THRESHOLD) {
        clearTimeout(state.singleFinger.timer);
        state.singleFinger.pending = false;
        state.singleFinger.isDragging = true;

        const touch = { x: clientX, y: clientY };
        const preTouch = { x: preX, y: preY };
        if (state.cursorMode.active) {
          const preCursor = {
            x: state.cursorMode.position.x,
            y: state.cursorMode.position.y,
          };
          dispatchMouseEvent(svgRect, "mousemove", preCursor, 0, state);
          moveCursor(state, dx, dy, svgRect, debugPanel);
        } else {
          dispatchMouseEvent(svgRect, "mousedown", preTouch, 2, state);
          dispatchMouseEvent(svgRect, "mousemove", touch, 2, state);
        }
      }
      return;
    }

    if (e.touches.length === 2 && state.twoFinger) {
      handleTwoFingerMove(state, e, svgRect, debugPanel);
    } else if (
      e.touches.length === 1 &&
      (state.singleFinger.isDragging ||
        state.leftMouseActive ||
        state.rightMouseActive ||
        state.cursorMode.active)
    ) {
      if (state.cursorMode.active) {
        const preX = state.singleFinger.event.touches[0].clientX;
        const preY = state.singleFinger.event.touches[0].clientY;
        const dx = clientX - preX;
        const dy = clientY - preY;
        moveCursor(state, dx, dy, svgRect, debugPanel);
        state.singleFinger.event = e;
      } else {
        logMessage(
          `Drag ${clientX.toFixed(1)}, ${clientY.toFixed(1)}`,
          debugPanel
        );
        // 单指拖动处理
        const touch = { x: clientX, y: clientY };
        const btn = getBtnByState(state, 2);
        dispatchMouseEvent(svgRect, "mousemove", touch, btn, state);
      }
    } else if (state.singleFinger.isSelecting) {
      const touch = { x: clientX, y: clientY };
      logMessage(
        `Selecting move: ${clientX.toFixed(1)}, ${clientY.toFixed(1)}`,
        debugPanel
      );
      dispatchMouseEvent(svgRect, "mousemove", touch, 0, state);
    }
  }

  // 双指移动处理
  function handleTwoFingerMove(state, e, svgRect, debugPanel) {
    const touch1 = { x: e.touches[0].clientX, y: e.touches[0].clientY };
    const touch2 = { x: e.touches[1].clientX, y: e.touches[1].clientY };
    const currMid = calculateMidpoint(touch1, touch2);
    const currDist = calculateDistance(touch1, touch2);

    e.preventDefault();
    handleZoomGesture(state, currDist, currMid, svgRect, debugPanel);

    // 更新触摸点状态
    state.twoFinger.touches = [touch1, touch2];
  }

  // 处理缩放手势
  function handleZoomGesture(state, currDist, currMid, svgRect, debugPanel) {
    const delta =
      (state.twoFinger.startDist - currDist) * CONFIG.ZOOM_SENSITIVITY;
    state.zoom.accumulator += delta;
    state.zoom.lastMid = currMid;
    state.twoFinger.startDist = currDist;

    if (Math.abs(state.zoom.accumulator) > CONFIG.ZOOM_MIN_DELTA) {
      logMessage(
        `Zooming: deltaY=${state.zoom.accumulator.toFixed(1)}`,
        debugPanel
      );

      const wheelEvent = new WheelEvent("wheel", {
        bubbles: true,
        cancelable: true,
        clientX: state.zoom.lastMid.x,
        clientY: state.zoom.lastMid.y,
        deltaY: state.zoom.accumulator,
        deltaMode: WheelEvent.DOM_DELTA_PIXEL,
        ctrlKey: false,
      });

      svgRect.dispatchEvent(wheelEvent);
      state.zoom.accumulator = 0;
    }
  }

  // 触摸结束处理
  function handleTouchEnd(state, svgRect, debugPanel, e) {
    clearSingleFingerState(state);

    if (e.touches.length === 1 && state.twoFinger) {
      logMessage("Two-finger touch ended", debugPanel);
      // 检查是否是双指点击
      if (state.twoFingerTap.startTime) {
        const touchDuration = Date.now() - state.twoFingerTap.startTime;
        const isQuickTap = touchDuration < CONFIG.ZOOM_MIN_DELAY;

        if (isQuickTap) {
          logMessage(
            `双指快速点击 (${touchDuration}ms) - 切换鼠标状态`,
            debugPanel
          );
          cycleMouseState(state, globalState.fabGroup, debugPanel);
        }
      }
    } else if (e.touches.length === 0) {
      if (e.changedTouches.length === 1) {
        if (state.cursorMode.active) {
          // In cursor mode, use the cursor position instead of touch position
          const touch = {
            x: state.cursorMode.position.x,
            y: state.cursorMode.position.y,
          };
          const button = getBtnByState(state, 0);

          logMessage(
            `Cursor mouseup&click: (${touch.x.toFixed(1)}, ${touch.y.toFixed(
              1
            )})`,
            debugPanel
          );
          dispatchMouseEvent(svgRect, "mouseup", touch, button, state);
          dispatchMouseEvent(svgRect, "click", touch, button, state);
        } else {
          const { clientX: x, clientY: y } = e.changedTouches[0];
          const touch = { x, y };

          if (state.singleFinger.isDragging) {
            logMessage("Drag ended", debugPanel);
            dispatchMouseEvent(svgRect, "mouseup", touch, 2, state);
          } else {
            const button = getBtnByState(state, 0);
            if (state.singleFinger.pending) {
              dispatchMouseEvent(svgRect, "mousedown", touch, button, state);
            }
            logMessage(
              `Touch ended (${button === 2 ? "right" : "left"} mouse)`,
              debugPanel
            );
            dispatchMouseEvent(svgRect, "mouseup", touch, button, state);
            dispatchMouseEvent(svgRect, "click", touch, button, state);
          }
        }
      }
    }

    resetGestureState(state);
  }

  // 触摸取消处理
  function handleTouchCancel(state, debugPanel) {
    logMessage("Touch cancelled", debugPanel);
    clearSingleFingerState(state);
    resetGestureState(state);
  }

  // 工具函数
  function calculateDistance(a, b) {
    return Math.hypot(a.x - b.x, a.y - b.y);
  }

  function calculateMidpoint(a, b) {
    return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
  }

  function dispatchMouseEvent(
    target,
    type,
    position,
    button = 0,
    { keyActive } = { keyActive: { ctrl: false } }
  ) {
    const buttonsMap = { 0: 1, 2: 2 };
    const event = new MouseEvent(type, {
      bubbles: true,
      cancelable: true,
      view: target.ownerDocument.defaultView,
      clientX: position.x,
      clientY: position.y,
      button: button,
      buttons: buttonsMap[button] || 0,
      ctrlKey: keyActive.ctrl,
      shiftKey: keyActive.shift,
      metaKey: keyActive.meta,
      altKey: keyActive.alt,
    });
    target.dispatchEvent(event);
  }

  function clearSingleFingerState(state) {
    if (state.singleFinger.timer) {
      clearTimeout(state.singleFinger.timer);
      state.singleFinger.timer = null;
    }
    state.singleFinger.pending = false;
  }

  function resetGestureState(state) {
    if (state.zoom.raf) {
      cancelAnimationFrame(state.zoom.raf);
      state.zoom.raf = null;
    }

    state.twoFinger = null;
    state.zoom.accumulator = 0;
    state.drag.active = false;
    state.drag.origin = null;
    state.longPress.active = false;
    state.singleFinger.isDragging = false;
    state.singleFinger.isSelecting = false;

    // 重置双指点击状态
    state.twoFingerTap.startTime = null;

    if (state.longPress.timer) {
      clearTimeout(state.longPress.timer);
      state.longPress.timer = null;
    }
    state.longPress.start = null;
  }

  // 新增：模拟键盘事件
  function triggerKey(target, key, type) {
    const keyMap = {
      meta: "Meta",
      ctrl: "Control",
      shift: "Shift",
    };
    const codeMap = {
      meta: "MetaLeft",
      ctrl: "ControlLeft",
      shift: "ShiftLeft",
      " ": "Space",
    };
    const event = new KeyboardEvent(type, {
      key: keyMap[key] || key,
      code: codeMap[key] || key,
      bubbles: true,
      cancelable: true,
      composed: true,
      ctrlKey: key === "ctrl",
      shiftKey: key === "shift",
      metaKey: key === "meta",
    });
    target.dispatchEvent(event);
  }

  // 主初始化函数
  function initTouchSupport() {
    try {
      const { debugPanel, fabGroup } = createDebugUI();
      globalState.debugPanel = debugPanel;
      globalState.fabGroup = fabGroup;

      // 绑定启用/禁用按钮事件
      const enableToggleBtn = fabGroup.querySelector(
        "#touch-fab-enable-toggle"
      );
      enableToggleBtn.addEventListener("click", () => {
        globalState.enabled = !globalState.enabled;
        enableToggleBtn.textContent = globalState.enabled ? "✓" : "🖱️";
        enableToggleBtn.classList.toggle("enabled", globalState.enabled);

        if (globalState.enabled) {
          logMessage("Touch support enabled - initializing...", debugPanel);
          initializeTouchSupport();
        } else {
          logMessage("Touch support disabled - cleaning up...", debugPanel);
          cleanupOverlays();
        }
      });

      logMessage(
        "Touch support UI ready - click the enable button to start",
        debugPanel
      );
    } catch (error) {
      console.error("Error during touch support initialization:", error);
    }
  }

  // 启动脚本
  if (navigator.userAgent.match(/(Mac|iPhone|iPod|iPad|Android)/i)) {
    // 确保DOM已经准备好
    if (document.readyState === "loading") {
      document.addEventListener("DOMContentLoaded", initTouchSupport);
    } else {
      initTouchSupport();
    }
  }
})();